﻿using log4net.Appender;
using log4net.Core;
using log4net_view.core.Log;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace log4netCustomAppender
{
    public class WinApiAppender : AppenderSkeleton
    {
        #region 字段
        private ArrayList fEventQueue;
        #endregion

        #region 属性
        private string windowReceiveTitle;

        /// <summary>
        /// 接收窗体标题
        /// </summary>
        public string WindowReceiveTitle
        {
            get { return this.windowReceiveTitle; }
            set { this.windowReceiveTitle = value; }
        }

        /// <summary>
        /// 队列大小
        /// </summary>
        private int queueSize = 1000;

        /// <summary>
        /// 队列大小
        /// </summary>
        public int QueueSize
        {
            get { return this.queueSize; }
            set { this.queueSize = value; }
        }
        #endregion

        public WinApiAppender() : base()
        {
            this.fEventQueue = new ArrayList();
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            lock (this.fEventQueue.SyncRoot)
            {
                this.fEventQueue.Add(loggingEvent);
                if (this.fEventQueue.Count > this.queueSize)
                {
                    this.Clear();
                }
            }
        }

        #region private 方法
        /// <summary>
        /// Clear the list of events
        /// </summary>
        /// <remarks>
        /// Clear the list of events
        /// </remarks>
        private void Clear()
        {
            lock (this.fEventQueue.SyncRoot)
            {
                this.SendMessage();
                this.fEventQueue.Clear();
            }
        }

        private void SendMessage()
        {
            lock (this.fEventQueue.SyncRoot)
            {
                if (!string.IsNullOrEmpty(this.windowReceiveTitle))
                {
                    List<LogMessage> logMessages = new List<LogMessage>();
                    foreach (LoggingEvent loggingEvent in this.fEventQueue)
                    {
                        LogMessage logMessage = this.CreateLogMessage(loggingEvent);
                        logMessages.Add(logMessage);
                    }

                    string json = Newtonsoft.Json.JsonConvert.SerializeObject(logMessages);
                    WinMessageHelper.Send(this.windowReceiveTitle, json);
                }
            }
        }

        /// <summary>
        /// 转换日志
        /// </summary>
        /// <param name="logEvent"></param>
        /// <returns></returns>
        private LogMessage CreateLogMessage(LoggingEvent logEvent)
        {
            LogMessage logMsg = new LogMessage();
            logMsg.RootLoggerName = logEvent.LoggerName;
            logMsg.LoggerName = logEvent.LoggerName;
            logMsg.ThreadName = logEvent.ThreadName;
            logMsg.Message = logEvent.RenderedMessage;
            logMsg.TimeStamp = logEvent.TimeStamp;
            logMsg.Level = LogUtils.GetLogLevelInfo(logEvent.Level.Value);

            // Per LoggingEvent.ExceptionObject, the exception object is not serialized, but the exception 
            // text is available through LoggingEvent.GetExceptionString
            logMsg.ExceptionString = logEvent.GetExceptionString();

            // Copy properties as string
            foreach (DictionaryEntry entry in logEvent.Properties)
            {
                if ((entry.Key == null) || (entry.Value == null))
                    continue;

                logMsg.Properties.Add(entry.Key.ToString(), entry.Value.ToString());
            }

            return logMsg;
        }
        #endregion
    }
}
